package com.ar4j.handler;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.antlr.stringtemplate.StringTemplate;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

import net.sf.cglib.proxy.MethodProxy;

import com.ar4j.ActiveRecord;
import com.ar4j.ActiveRecordContext;
import com.ar4j.ActiveRecordMetadata;
import com.ar4j.sql.ExtendedMapSqlParameterSource;
import com.ar4j.sql.SqlUtils;

/**
 * A handler for active record find operations
 */
public class DeleteMethodHandler extends NoOpMethodHandler {
  private static final StringTemplate QUERY_TEMPLATE = new StringTemplate(
      "DELETE FROM $qualifiedTable$ $where$"
    ); 
  
  @SuppressWarnings("unchecked")
  @Override
  public Object intercept(ActiveRecordMetadata metadata, ActiveRecordContext context, Object target, Method method, Object[] args, MethodProxy proxy) 
    throws Throwable {

    // make sure we have a template first
    if(context.getSimpleTemplate() == null) {
      throw new IllegalStateException("Cannot execute delete on an active record that does not have a datasource set");
    }
    
    // detect whether there is a map of parameter fields or we are deleting the current record
    ActiveRecord<?> record = (ActiveRecord<?>) target;
    Map<String, Object> parameters = new HashMap<String, Object>();
    boolean singleDelete = false;
    if(args.length == 0) {
      parameters.put(metadata.getIdentifierPropertyName(), record.getIdentifier());
      singleDelete = true;
    } else {
      parameters = (Map<String, Object>) args[0];
    }
    
    // process into parameters
    Collection<String> fields = new HashSet<String>();
    Collection<String> collectionFields = new HashSet<String>();
    HandlerUtils.scanParametersForFields(parameters, metadata, fields, collectionFields);
    
    // compose query and execute the delete
    ExtendedMapSqlParameterSource source = new ExtendedMapSqlParameterSource(parameters, metadata.getPropertyTypeConvertorMap());
    String sql = HandlerUtils.renderQueryWithWhere(QUERY_TEMPLATE, 
        metadata, 
        context, 
        SqlUtils.composeWhereClause(fields, collectionFields, null, metadata.getPropertyColumnNameMap()));
    
    
    int result = context.getSimpleTemplate().update(sql, source);
    if(singleDelete) {
      record.setProperty(metadata.getIdentifierPropertyName(), null);
      return (result == 1);
    } else {
      return result;
    }
  }
  
  @Override
  public String toString() {
    return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
  }

}
